<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>手绘板</title>
    <style>
        canvas {
            border: #aaaaaa 1px solid;
            padding: 0;
        }

        .button {
            text-align: right;
            width: 800px;
        }
    </style>
</head>
<body>
<canvas id="cvs" width="800" height="500"></canvas>
<div class="button">
    <button id="clear">clear</button>
    <button id="undo">undo</button>
    <button id="redo">redo</button>
    <button id="save">save</button>
</div>
<img src="" alt="" id="result">
</body>
</html>
<script>
    window.onload = () => {
        let cvs = document.getElementById("cvs");
        let ctx = cvs.getContext('2d');
        let isDrawing = false;
        let isMouseDown = false;
        let executionArray = [];
        let redoArray = [];
        let nowOption = [];
        let outPage = null;
        let isClear = false;

        cvs.addEventListener("mousedown", (page) => {
            isDrawing = true;
            isMouseDown = true;
            ctx.moveTo(page.x, page.y);
            recordStartPoint(page);
        })
        cvs.addEventListener("mousemove", (page) => {
            if (isDrawing) {
                drawLine(page);
                recordLinePoint(page);
            }
        })

        cvs.addEventListener("mouseenter", (page) => {
            if (isMouseDown) {
                isDrawing = true;
                ctx.moveTo(page.x, page.y);
                recordStartPoint(page);
            }
        })
        cvs.addEventListener("mouseout", (page) => {
            if (isDrawing) {
                outPage = page;
            }
        })
        cvs.addEventListener("mouseup", (page) => {
            recordEndPoint(page);
        })
        document.onmouseup = () => {
            if (outPage !== null) {
                recordEndPoint(outPage);
                outPage = null;
            }
            isMouseDown = false;
            isDrawing = false;
        }

        document.onmousedown = () => {
            isDrawing = true;
            isMouseDown = true;
        }

        document.getElementById("clear").addEventListener("click", () => {
            clearCanvas();
        })

        document.getElementById("save").addEventListener("click", () => {
            let dataURL = cvs.toDataURL("image/png");
            document.getElementById("result").src = dataURL;
            console.log(dataURL);
        })

        document.getElementById("undo").addEventListener("click", () => {
            let pop = executionArray.pop();
            if (pop) {
                redoArray.push(pop);
            }
            redraw();
        })
        document.getElementById("redo").addEventListener("click", () => {
            if (redoArray.length === 0) return;
            let pop = redoArray.pop();
            executionArray.push(pop);
            redraw();
        })

        let redraw = () => {
            clearCanvas(false);
            for (let exec of executionArray) {
                for (let e of exec) {
                    switch (e.method) {
                        case "moveTo":
                            ctx.moveTo(e.page.x, e.page.y);
                            break;
                        case "lineTo":
                            drawLine(e.page);
                            break;
                        case "end":
                            drawLine(e.page);
                            break;
                        case "clear":
                            clearCanvas(false);
                            break;
                    }
                }
            }
        }
        let drawLine = (page) => {
            ctx.lineTo(page.x, page.y);
            ctx.lineCap = "round";
            ctx.lineWidth = 4;
            ctx.stroke();
        }

        let clearCanvas = (record = true) => {
            ctx.clearRect(0, 0, 800, 500);
            ctx.beginPath();
            if (record) {
                executionArray.push([{
                    method: "clear",
                }]);
            }
        }
        let recordStartPoint = (page) => {
            nowOption.push({
                method: "moveTo",
                page: page,
            });
            redoArray = [];
        }
        let recordLinePoint = (page) => {
            nowOption.push({
                method: "lineTo",
                page: page,
            });
        }
        let recordEndPoint = (page) => {
            nowOption.push({
                method: "end",
                page: page,
            });
            executionArray.push(nowOption);
            nowOption = [];
            console.log(executionArray, nowOption);
        }
    }
</script>